home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 22 / PCPP #22.iso / Quake2 / q2source_12_11 / utils3 / qdata / models.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-12-03  |  23.4 KB  |  1,132 lines

  1.  
  2. #include "qdata.h"
  3.  
  4. //=================================================================
  5.  
  6. typedef struct 
  7. {
  8.     int        numnormals;
  9.     vec3_t    normalsum;
  10. } vertexnormals_t;
  11.  
  12. typedef struct
  13. {
  14.     vec3_t        v;
  15.     int            lightnormalindex;
  16. } trivert_t;
  17.  
  18. typedef struct
  19. {
  20.     vec3_t        mins, maxs;
  21.     char        name[16];
  22.     trivert_t    v[MAX_VERTS];
  23. } frame_t;
  24.  
  25. //================================================================
  26.  
  27. frame_t        g_frames[MAX_FRAMES];
  28.  
  29. dmdl_t        model;
  30.  
  31.  
  32. float        scale_up;            // set by $scale
  33. vec3_t        adjust;                // set by $origin
  34. int            g_fixedwidth, g_fixedheight;    // set by $skinsize
  35.  
  36.  
  37. //
  38. // base frame info
  39. //
  40. vec3_t        base_xyz[MAX_VERTS];
  41. dstvert_t    base_st[MAX_VERTS];
  42. dtriangle_t    triangles[MAX_TRIANGLES];
  43.  
  44. int            triangle_st[MAX_TRIANGLES][3][2];
  45.  
  46. // the command list holds counts, s/t values, and xyz indexes
  47. // that are valid for every frame
  48. int            commands[16384];
  49. int            numcommands;
  50. int            numglverts;
  51. int            used[MAX_TRIANGLES];
  52.  
  53. char        g_skins[MAX_MD2SKINS][64];
  54.  
  55. char        cdarchive[1024];
  56. char        cdpartial[1024];
  57. char        cddir[1024];
  58.  
  59. char        modelname[64];    // empty unless $modelname issued (players)
  60.  
  61. #define NUMVERTEXNORMALS    162
  62.  
  63. float    avertexnormals[NUMVERTEXNORMALS][3] = {
  64. #include "anorms.h"
  65. };
  66.  
  67. FILE    *headerouthandle = NULL;
  68.  
  69. //==============================================================
  70.  
  71. /*
  72. ===============
  73. ClearModel
  74. ===============
  75. */
  76. void ClearModel (void)
  77. {
  78.     memset (&model, 0, sizeof(model));
  79.  
  80.     modelname[0] = 0;
  81.     scale_up = 1.0;    
  82.     VectorCopy (vec3_origin, adjust);
  83.     g_fixedwidth = g_fixedheight = 0;
  84.     g_skipmodel = false;
  85. }
  86.  
  87.  
  88. void H_printf(char *fmt, ...)
  89. {
  90.     va_list argptr;
  91.     char    name[1024];
  92.  
  93.     if (!headerouthandle)
  94.     {
  95.         sprintf (name, "%s/tris.h", cddir);
  96.         headerouthandle = SafeOpenWrite (name);
  97.         fprintf(headerouthandle, "// %s\n\n", cddir);
  98.         fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n");
  99.     }
  100.  
  101.     va_start (argptr, fmt);
  102.     vfprintf (headerouthandle, fmt, argptr);
  103.     va_end (argptr);
  104. }
  105.  
  106.  
  107. /*
  108. ============
  109. WriteModelFile
  110. ============
  111. */
  112. void WriteModelFile (FILE *modelouthandle)
  113. {
  114.     int                i;
  115.     dmdl_t            modeltemp;
  116.     int                j, k;
  117.     frame_t            *in;
  118.     daliasframe_t    *out;
  119.     byte            buffer[MAX_VERTS*4+128];
  120.     float            v;
  121.     int                c_on, c_off;
  122.  
  123.     model.ident = IDALIASHEADER;
  124.     model.version = ALIAS_VERSION;
  125.     model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];
  126.     model.num_glcmds = numcommands;
  127.     model.ofs_skins = sizeof(dmdl_t);
  128.     model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
  129.     model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);
  130.     model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);
  131.     model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;
  132.     model.ofs_end = model.ofs_glcmds + model.num_glcmds*4;
  133.  
  134.     //
  135.     // write out the model header
  136.     //
  137.     for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
  138.         ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);
  139.  
  140.     SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
  141.  
  142.     //
  143.     // write out the skin names
  144.     //
  145.     SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);
  146.  
  147.     //
  148.     // write out the texture coordinates
  149.     //
  150.     c_on = c_off = 0;
  151.     for (i=0 ; i<model.num_st ; i++)
  152.     {
  153.         base_st[i].s = LittleShort (base_st[i].s);
  154.         base_st[i].t = LittleShort (base_st[i].t);
  155.     }
  156.  
  157.     SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));
  158.  
  159.     //
  160.     // write out the triangles
  161.     //
  162.     for (i=0 ; i<model.num_tris ; i++)
  163.     {
  164.         int            j;
  165.         dtriangle_t    tri;
  166.  
  167.         for (j=0 ; j<3 ; j++)
  168.         {
  169.             tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);
  170.             tri.index_st[j] = LittleShort (triangles[i].index_st[j]);
  171.         }
  172.  
  173.         SafeWrite (modelouthandle, &tri, sizeof(tri));
  174.     }
  175.  
  176.     //
  177.     // write out the frames
  178.     //
  179.     for (i=0 ; i<model.num_frames ; i++)
  180.     {
  181.         in = &g_frames[i];
  182.         out = (daliasframe_t *)buffer;
  183.  
  184.         strcpy (out->name, in->name);
  185.         for (j=0 ; j<3 ; j++)
  186.         {
  187.             out->scale[j] = (in->maxs[j] - in->mins[j])/255;
  188.             out->translate[j] = in->mins[j];
  189.         }
  190.  
  191.         for (j=0 ; j<model.num_xyz ; j++)
  192.         {
  193.         // all of these are byte values, so no need to deal with endianness
  194.             out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
  195.  
  196.             for (k=0 ; k<3 ; k++)
  197.             {
  198.             // scale to byte values & min/max check
  199.                 v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );
  200.  
  201.             // clamp, so rounding doesn't wrap from 255.6 to 0
  202.                 if (v > 255.0)
  203.                     v = 255.0;
  204.                 if (v < 0)
  205.                     v = 0;
  206.                 out->verts[j].v[k] = v;
  207.             }
  208.         }
  209.  
  210.         for (j=0 ; j<3 ; j++)
  211.         {
  212.             out->scale[j] = LittleFloat (out->scale[j]);
  213.             out->translate[j] = LittleFloat (out->translate[j]);
  214.         }
  215.  
  216.         SafeWrite (modelouthandle, out, model.framesize);
  217.     }
  218.  
  219.     //
  220.     // write out glcmds
  221.     //
  222.     SafeWrite (modelouthandle, commands, numcommands*4);
  223. }
  224.  
  225.  
  226. /*
  227. ===============
  228. FinishModel
  229. ===============
  230. */
  231. void FinishModel (void)
  232. {
  233.     FILE        *modelouthandle;
  234.     int            i;
  235.     char        name[1024];
  236.     
  237.     if (!model.num_frames)
  238.         return;
  239.     
  240. //
  241. // copy to release directory tree if doing a release build
  242. //
  243.     if (g_release)
  244.     {
  245.         if (modelname[0])
  246.             sprintf (name, "%s", modelname);
  247.         else
  248.             sprintf (name, "%s/tris.md2", cdpartial);
  249.         ReleaseFile (name);
  250.  
  251.         for (i=0 ; i<model.num_skins ; i++)
  252.         {
  253.             ReleaseFile (g_skins[i]);
  254.         }
  255.         model.num_frames = 0;
  256.         return;
  257.     }
  258.     
  259. //
  260. // write the model output file
  261. //
  262.     if (modelname[0])
  263.         sprintf (name, "%s%s", gamedir, modelname);
  264.     else
  265.         sprintf (name, "%s/tris.md2", cddir);
  266.     printf ("saving to %s\n", name);
  267.     CreatePath (name);
  268.     modelouthandle = SafeOpenWrite (name);
  269.  
  270.     WriteModelFile (modelouthandle);
  271.     
  272.     printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight);
  273.     printf ("%4d vertexes\n", model.num_xyz);
  274.     printf ("%4d triangles\n", model.num_tris);
  275.     printf ("%4d frame\n", model.num_frames);
  276.     printf ("%4d glverts\n", numglverts);
  277.     printf ("%4d glcmd\n", model.num_glcmds);
  278.     printf ("%4d skins\n", model.num_skins);
  279.     printf ("file size: %d\n", (int)ftell (modelouthandle) );
  280.     printf ("---------------------\n");
  281.     
  282.     fclose (modelouthandle);
  283.  
  284.     // finish writing header file
  285.     H_printf("\n");
  286.  
  287.     // scale_up is usefull to allow step distances to be adjusted
  288.     H_printf("#define MODEL_SCALE\t\t%f\n", scale_up);
  289.  
  290.     fclose (headerouthandle);
  291.     headerouthandle = NULL;
  292. }
  293.  
  294.  
  295. /*
  296. =================================================================
  297.  
  298. ALIAS MODEL DISPLAY LIST GENERATION
  299.  
  300. =================================================================
  301. */
  302.  
  303. int        strip_xyz[128];
  304. int        strip_st[128];
  305. int        strip_tris[128];
  306. int        stripcount;
  307.  
  308. /*
  309. ================
  310. StripLength
  311. ================
  312. */
  313. int    StripLength (int starttri, int startv)
  314. {
  315.     int            m1, m2;
  316.     int            st1, st2;
  317.     int            j;
  318.     dtriangle_t    *last, *check;
  319.     int            k;
  320.  
  321.     used[starttri] = 2;
  322.  
  323.     last = &triangles[starttri];
  324.  
  325.     strip_xyz[0] = last->index_xyz[(startv)%3];
  326.     strip_xyz[1] = last->index_xyz[(startv+1)%3];
  327.     strip_xyz[2] = last->index_xyz[(startv+2)%3];
  328.     strip_st[0] = last->index_st[(startv)%3];
  329.     strip_st[1] = last->index_st[(startv+1)%3];
  330.     strip_st[2] = last->index_st[(startv+2)%3];
  331.  
  332.     strip_tris[0] = starttri;
  333.     stripcount = 1;
  334.  
  335.     m1 = last->index_xyz[(startv+2)%3];
  336.     st1 = last->index_st[(startv+2)%3];
  337.     m2 = last->index_xyz[(startv+1)%3];
  338.     st2 = last->index_st[(startv+1)%3];
  339.  
  340.     // look for a matching triangle
  341. nexttri:
  342.     for (j=starttri+1, check=&triangles[starttri+1]
  343.         ; j<model.num_tris ; j++, check++)
  344.     {
  345.         for (k=0 ; k<3 ; k++)
  346.         {
  347.             if (check->index_xyz[k] != m1)
  348.                 continue;
  349.             if (check->index_st[k] != st1)
  350.                 continue;
  351.             if (check->index_xyz[ (k+1)%3 ] != m2)
  352.                 continue;
  353.             if (check->index_st[ (k+1)%3 ] != st2)
  354.                 continue;
  355.  
  356.             // this is the next part of the fan
  357.  
  358.             // if we can't use this triangle, this tristrip is done
  359.             if (used[j])
  360.                 goto done;
  361.  
  362.             // the new edge
  363.             if (stripcount & 1)
  364.             {
  365.                 m2 = check->index_xyz[ (k+2)%3 ];
  366.                 st2 = check->index_st[ (k+2)%3 ];
  367.             }
  368.             else
  369.             {
  370.                 m1 = check->index_xyz[ (k+2)%3 ];
  371.                 st1 = check->index_st[ (k+2)%3 ];
  372.             }
  373.  
  374.             strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ];
  375.             strip_st[stripcount+2] = check->index_st[ (k+2)%3 ];
  376.             strip_tris[stripcount] = j;
  377.             stripcount++;
  378.  
  379.             used[j] = 2;
  380.             goto nexttri;
  381.         }
  382.     }
  383. done:
  384.  
  385.     // clear the temp used flags
  386.     for (j=starttri+1 ; j<model.num_tris ; j++)
  387.         if (used[j] == 2)
  388.             used[j] = 0;
  389.  
  390.     return stripcount;
  391. }
  392.  
  393.  
  394. /*
  395. ===========
  396. FanLength
  397. ===========
  398. */
  399. int    FanLength (int starttri, int startv)
  400. {
  401.     int        m1, m2;
  402.     int        st1, st2;
  403.     int        j;
  404.     dtriangle_t    *last, *check;
  405.     int        k;
  406.  
  407.     used[starttri] = 2;
  408.  
  409.     last = &triangles[starttri];
  410.  
  411.     strip_xyz[0] = last->index_xyz[(startv)%3];
  412.     strip_xyz[1] = last->index_xyz[(startv+1)%3];
  413.     strip_xyz[2] = last->index_xyz[(startv+2)%3];
  414.     strip_st[0] = last->index_st[(startv)%3];
  415.     strip_st[1] = last->index_st[(startv+1)%3];
  416.     strip_st[2] = last->index_st[(startv+2)%3];
  417.  
  418.     strip_tris[0] = starttri;
  419.     stripcount = 1;
  420.  
  421.     m1 = last->index_xyz[(startv+0)%3];
  422.     st1 = last->index_st[(startv+0)%3];
  423.     m2 = last->index_xyz[(startv+2)%3];
  424.     st2 = last->index_st[(startv+2)%3];
  425.  
  426.  
  427.     // look for a matching triangle
  428. nexttri:
  429.     for (j=starttri+1, check=&triangles[starttri+1] 
  430.         ; j<model.num_tris ; j++, check++)
  431.     {
  432.         for (k=0 ; k<3 ; k++)
  433.         {
  434.             if (check->index_xyz[k] != m1)
  435.                 continue;
  436.             if (check->index_st[k] != st1)
  437.                 continue;
  438.             if (check->index_xyz[ (k+1)%3 ] != m2)
  439.                 continue;
  440.             if (check->index_st[ (k+1)%3 ] != st2)
  441.                 continue;
  442.  
  443.             // this is the next part of the fan
  444.  
  445.             // if we can't use this triangle, this tristrip is done
  446.             if (used[j])
  447.                 goto done;
  448.  
  449.             // the new edge
  450.             m2 = check->index_xyz[ (k+2)%3 ];
  451.             st2 = check->index_st[ (k+2)%3 ];
  452.  
  453.             strip_xyz[stripcount+2] = m2;
  454.             strip_st[stripcount+2] = st2;
  455.             strip_tris[stripcount] = j;
  456.             stripcount++;
  457.  
  458.             used[j] = 2;
  459.             goto nexttri;
  460.         }
  461.     }
  462. done:
  463.  
  464.     // clear the temp used flags
  465.     for (j=starttri+1 ; j<model.num_tris ; j++)
  466.         if (used[j] == 2)
  467.             used[j] = 0;
  468.  
  469.     return stripcount;
  470. }
  471.  
  472.  
  473.  
  474. /*
  475. ================
  476. BuildGlCmds
  477.  
  478. Generate a list of trifans or strips
  479. for the model, which holds for all frames
  480. ================
  481. */
  482. void BuildGlCmds (void)
  483. {
  484.     int        i, j, k;
  485.     int        startv;
  486.     float    s, t;
  487.     int        len, bestlen, besttype;
  488.     int        best_xyz[1024];
  489.     int        best_st[1024];
  490.     int        best_tris[1024];
  491.     int        type;
  492.  
  493.     //
  494.     // build tristrips
  495.     //
  496.     numcommands = 0;
  497.     numglverts = 0;
  498.     memset (used, 0, sizeof(used));
  499.     for (i=0 ; i<model.num_tris ; i++)
  500.     {
  501.         // pick an unused triangle and start the trifan
  502.         if (used[i])
  503.             continue;
  504.  
  505.         bestlen = 0;
  506.         for (type = 0 ; type < 2 ; type++)
  507. //    type = 1;
  508.         {
  509.             for (startv =0 ; startv < 3 ; startv++)
  510.             {
  511.                 if (type == 1)
  512.                     len = StripLength (i, startv);
  513.                 else
  514.                     len = FanLength (i, startv);
  515.                 if (len > bestlen)
  516.                 {
  517.                     besttype = type;
  518.                     bestlen = len;
  519.                     for (j=0 ; j<bestlen+2 ; j++)
  520.                     {
  521.                         best_st[j] = strip_st[j];
  522.                         best_xyz[j] = strip_xyz[j];
  523.                     }
  524.                     for (j=0 ; j<bestlen ; j++)
  525.                         best_tris[j] = strip_tris[j];
  526.                 }
  527.             }
  528.         }
  529.  
  530.         // mark the tris on the best strip/fan as used
  531.         for (j=0 ; j<bestlen ; j++)
  532.             used[best_tris[j]] = 1;
  533.  
  534.         if (besttype == 1)
  535.             commands[numcommands++] = (bestlen+2);
  536.         else
  537.             commands[numcommands++] = -(bestlen+2);
  538.  
  539.         numglverts += bestlen+2;
  540.  
  541.         for (j=0 ; j<bestlen+2 ; j++)
  542.         {
  543.             // emit a vertex into the reorder buffer
  544.             k = best_st[j];
  545.  
  546.             // emit s/t coords into the commands stream
  547.             s = base_st[k].s;
  548.             t = base_st[k].t;
  549.  
  550.             s = (s + 0.5) / model.skinwidth;
  551.             t = (t + 0.5) / model.skinheight;
  552.  
  553.             *(float *)&commands[numcommands++] = s;
  554.             *(float *)&commands[numcommands++] = t;
  555.             *(int *)&commands[numcommands++] = best_xyz[j];
  556.         }
  557.     }
  558.  
  559.     commands[numcommands++] = 0;        // end of list marker
  560. }
  561.  
  562.  
  563. /*
  564. ===============================================================
  565.  
  566. BASE FRAME SETUP
  567.  
  568. ===============================================================
  569. */
  570.  
  571. /*
  572. ============
  573. BuildST
  574.  
  575. Builds the triangle_st array for the base frame and
  576. model.skinwidth / model.skinheight
  577.  
  578.   FIXME: allow this to be loaded from a file for
  579.   arbitrary mappings
  580. ============
  581. */
  582. void BuildST (triangle_t *ptri, int numtri)
  583. {
  584.     int            i, j;
  585.     int            width, height, iwidth, iheight, swidth;
  586.     float        basex, basey;
  587.     float        s_scale, t_scale;
  588.     float        scale;
  589.     vec3_t        mins, maxs;
  590.     float        *pbasevert;
  591.     vec3_t        vtemp1, vtemp2, normal;
  592.  
  593.     //
  594.     // find bounds of all the verts on the base frame
  595.     //
  596.     ClearBounds (mins, maxs);
  597.     
  598.     for (i=0 ; i<numtri ; i++)
  599.         for (j=0 ; j<3 ; j++)
  600.             AddPointToBounds (ptri[i].verts[j], mins, maxs);
  601.     
  602.     for (i=0 ; i<3 ; i++)
  603.     {
  604.         mins[i] = floor(mins[i]);
  605.         maxs[i] = ceil(maxs[i]);
  606.     }
  607.     
  608.     width = maxs[0] - mins[0];
  609.     height = maxs[2] - mins[2];
  610.  
  611.     if (!g_fixedwidth)
  612.     {    // old style
  613.         scale = 8;
  614.         if (width*scale >= 150)
  615.             scale = 150.0 / width;    
  616.         if (height*scale >= 190)
  617.             scale = 190.0 / height;
  618.  
  619.         s_scale = t_scale = scale;
  620.  
  621.         iwidth = ceil(width*s_scale);
  622.         iheight = ceil(height*t_scale);
  623.  
  624.         iwidth += 4;
  625.         iheight += 4;
  626.     }
  627.     else
  628.     {    // new style
  629.         iwidth = g_fixedwidth / 2;
  630.         iheight = g_fixedheight;
  631.  
  632.         s_scale = (float)(iwidth-4) / width;
  633.         t_scale = (float)(iheight-4) / height;
  634.     }
  635.  
  636. //
  637. // determine which side of each triangle to map the texture to
  638. //
  639.     for (i=0 ; i<numtri ; i++)
  640.     {
  641.         VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
  642.         VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
  643.         CrossProduct (vtemp1, vtemp2, normal);
  644.  
  645.         if (normal[1] > 0)
  646.         {
  647.             basex = iwidth + 2;
  648.         }
  649.         else
  650.         {
  651.             basex = 2;
  652.         }
  653.         basey = 2;
  654.         
  655.         for (j=0 ; j<3 ; j++)
  656.         {
  657.             pbasevert = ptri[i].verts[j];
  658.  
  659.             triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);
  660.             triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);
  661.         }
  662.     }
  663.  
  664. // make the width a multiple of 4; some hardware requires this, and it ensures
  665. // dword alignment for each scan
  666.     swidth = iwidth*2;
  667.     model.skinwidth = (swidth + 3) & ~3;
  668.     model.skinheight = iheight;
  669. }
  670.  
  671.  
  672. /*
  673. =================
  674. Cmd_Base
  675. =================
  676. */
  677. void Cmd_Base (void)
  678. {
  679.     triangle_t    *ptri;
  680.     int            i, j, k;
  681.     int        time1;
  682.     char    file1[1024];
  683.  
  684.     GetToken (false);
  685.  
  686.     if (g_skipmodel || g_release || g_archive)
  687.         return;
  688.  
  689.     printf ("---------------------\n");
  690.     sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext);
  691.     printf ("%s\n", file1);
  692.  
  693.     ExpandPathAndArchive (file1);
  694.  
  695.     sprintf (file1, "%s/%s.%s", cddir, token, trifileext);
  696.  
  697.     time1 = FileTime (file1);
  698.     if (time1 == -1)
  699.         Error ("%s doesn't exist", file1);
  700.  
  701. //
  702. // load the base triangles
  703. //
  704.     if (do3ds)
  705.         Load3DSTriangleList (file1, &ptri, &model.num_tris);
  706.     else
  707.         LoadTriangleList (file1, &ptri, &model.num_tris);
  708.  
  709. //
  710. // get the ST values
  711. //
  712.     BuildST (ptri, model.num_tris);
  713.  
  714. //
  715. // run through all the base triangles, storing each unique vertex in the
  716. // base vertex list and setting the indirect triangles to point to the base
  717. // vertices
  718. //
  719.     for (i=0 ; i<model.num_tris ; i++)
  720.     {
  721.         for (j=0 ; j<3 ; j++)
  722.         {
  723.             // get the xyz index
  724.             for (k=0 ; k<model.num_xyz ; k++)
  725.                 if (VectorCompare (ptri[i].verts[j], base_xyz[k]))
  726.                     break;    // this vertex is already in the base vertex list
  727.  
  728.             if (k == model.num_xyz)
  729.             { // new index
  730.                 VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]);
  731.                 model.num_xyz++;
  732.             }
  733.  
  734.             triangles[i].index_xyz[j] = k;
  735.  
  736.             // get the st index
  737.             for (k=0 ; k<model.num_st ; k++)
  738.                 if (triangle_st[i][j][0] == base_st[k].s
  739.                 && triangle_st[i][j][1] == base_st[k].t)
  740.                     break;    // this vertex is already in the base vertex list
  741.  
  742.             if (k == model.num_st)
  743.             { // new index
  744.                 base_st[model.num_st].s = triangle_st[i][j][0];
  745.                 base_st[model.num_st].t = triangle_st[i][j][1];
  746.                 model.num_st++;
  747.             }
  748.  
  749.             triangles[i].index_st[j] = k;
  750.         }
  751.     }
  752.  
  753.     // build triangle strips / fans
  754.     BuildGlCmds ();
  755. }
  756.  
  757. //===============================================================
  758.  
  759. char    *FindFrameFile (char *frame)
  760. {
  761.     int            time1;
  762.     char    file1[1024];
  763.     static char    retname[1024];
  764.     char    base[32];
  765.     char    suffix[32];
  766.     char    *s;
  767.  
  768.     if (strstr (frame, "."))
  769.         return frame;        // allready in dot format
  770.  
  771.     // split 'run1' into 'run' and '1'
  772.     s = frame + strlen(frame)-1;
  773.  
  774.     while (s != frame && *s >= '0' && *s <= '9')
  775.         s--;
  776.  
  777.     strcpy (suffix, s+1);
  778.     strcpy (base, frame);
  779.     base[s-frame+1] = 0;
  780.  
  781.     // check for 'run1.tri'
  782.     sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, trifileext);
  783.     time1 = FileTime (file1);
  784.     if (time1 != -1)
  785.     {
  786.         sprintf (retname, "%s%s.%s", base, suffix, trifileext);
  787.         return retname;
  788.     }
  789.  
  790.     // check for 'run.1'
  791.     sprintf (file1, "%s/%s.%s",cddir, base, suffix);
  792.     time1 = FileTime (file1);
  793.     if (time1 != -1)
  794.     {
  795.         sprintf (retname, "%s.%s", base, suffix);
  796.         return retname;
  797.     }
  798.  
  799.     Error ("frame %s could not be found",frame);
  800.     return NULL;
  801. }
  802.  
  803. /*
  804. ===============
  805. GrabFrame
  806. ===============
  807. */
  808. void GrabFrame (char *frame)
  809. {
  810.     triangle_t    *ptri;
  811.     int            i, j;
  812.     trivert_t    *ptrivert;
  813.     int            num_tris;
  814.     char        file1[1024];
  815.     frame_t        *fr;
  816.     vertexnormals_t    vnorms[MAX_VERTS];
  817.     int        index_xyz;
  818.     char    *framefile;
  819.  
  820.     // the frame 'run1' will be looked for as either
  821.     // run.1 or run1.tri, so the new alias sequence save
  822.     // feature an be used
  823.     framefile = FindFrameFile (frame);
  824.  
  825.     sprintf (file1, "%s/%s", cdarchive, framefile);
  826.     ExpandPathAndArchive (file1);
  827.  
  828.     sprintf (file1, "%s/%s",cddir, framefile);
  829.  
  830.     printf ("grabbing %s\n", file1);
  831.  
  832.     if (model.num_frames >= MAX_FRAMES)
  833.         Error ("model.num_frames >= MAX_FRAMES");
  834.     fr = &g_frames[model.num_frames];
  835.     model.num_frames++;
  836.  
  837.     strcpy (fr->name, frame);
  838.  
  839. //
  840. // load the frame
  841. //
  842.     if (do3ds)
  843.         Load3DSTriangleList (file1, &ptri, &num_tris);
  844.     else
  845.         LoadTriangleList (file1, &ptri, &num_tris);
  846.  
  847.     if (num_tris != model.num_tris)
  848.         Error ("%s: number of triangles doesn't match base frame\n", file1);
  849.  
  850. //
  851. // allocate storage for the frame's vertices
  852. //
  853.     ptrivert = fr->v;
  854.  
  855.     for (i=0 ; i<model.num_xyz ; i++)
  856.     {
  857.         vnorms[i].numnormals = 0;
  858.         VectorClear (vnorms[i].normalsum);
  859.     }
  860.     ClearBounds (fr->mins, fr->maxs);
  861.  
  862. //
  863. // store the frame's vertices in the same order as the base. This assumes the
  864. // triangles and vertices in this frame are in exactly the same order as in the
  865. // base
  866. //
  867.     for (i=0 ; i<num_tris ; i++)
  868.     {
  869.         vec3_t    vtemp1, vtemp2, normal;
  870.         float    ftemp;
  871.  
  872.         VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
  873.         VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
  874.         CrossProduct (vtemp1, vtemp2, normal);
  875.  
  876.         VectorNormalize (normal, normal);
  877.  
  878.     // rotate the normal so the model faces down the positive x axis
  879.         ftemp = normal[0];
  880.         normal[0] = -normal[1];
  881.         normal[1] = ftemp;
  882.  
  883.         for (j=0 ; j<3 ; j++)
  884.         {
  885.             index_xyz = triangles[i].index_xyz[j];
  886.  
  887.         // rotate the vertices so the model faces down the positive x axis
  888.         // also adjust the vertices to the desired origin
  889.             ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) +
  890.                                         adjust[0];
  891.             ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) +
  892.                                         adjust[1];
  893.             ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) +
  894.                                         adjust[2];
  895.  
  896.             AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
  897.  
  898.             VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum);
  899.             vnorms[index_xyz].numnormals++;
  900.         }
  901.     }
  902.  
  903. //
  904. // calculate the vertex normals, match them to the template list, and store the
  905. // index of the best match
  906. //
  907.     for (i=0 ; i<model.num_xyz ; i++)
  908.     {
  909.         int        j;
  910.         vec3_t    v;
  911.         float    maxdot;
  912.         int        maxdotindex;
  913.         int        c;
  914.  
  915.         c = vnorms[i].numnormals;
  916.         if (!c)
  917.             Error ("Vertex with no triangles attached");
  918.  
  919.         VectorScale (vnorms[i].normalsum, 1.0/c, v);
  920.         VectorNormalize (v, v);
  921.  
  922.         maxdot = -999999.0;
  923.         maxdotindex = -1;
  924.  
  925.         for (j=0 ; j<NUMVERTEXNORMALS ; j++)
  926.         {
  927.             float    dot;
  928.  
  929.             dot = DotProduct (v, avertexnormals[j]);
  930.             if (dot > maxdot)
  931.             {
  932.                 maxdot = dot;
  933.                 maxdotindex = j;
  934.             }
  935.         }
  936.  
  937.         ptrivert[i].lightnormalindex = maxdotindex;
  938.     }
  939.  
  940.     free (ptri);
  941. }
  942.  
  943. /*
  944. ===============
  945. Cmd_Frame    
  946. ===============
  947. */
  948. void Cmd_Frame (void)
  949. {
  950.     while (TokenAvailable())
  951.     {
  952.         GetToken (false);
  953.         if (g_skipmodel)
  954.             continue;
  955.         if (g_release || g_archive)
  956.         {
  957.             model.num_frames = 1;    // don't skip the writeout
  958.             continue;
  959.         }
  960.  
  961.         H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames);
  962.  
  963.         GrabFrame (token);
  964.     }
  965. }
  966.  
  967.  
  968. /*
  969. ===============
  970. Cmd_Skin
  971.  
  972. Skins aren't actually stored in the file, only a reference
  973. is saved out to the header file.
  974. ===============
  975. */
  976. void Cmd_Skin (void)
  977. {
  978.     byte    *palette;
  979.     byte    *pixels;
  980.     int        width, height;
  981.     byte    *cropped;
  982.     int        y;
  983.     char    name[1024], savename[1024];
  984.  
  985.     GetToken (false);
  986.  
  987.     if (model.num_skins == MAX_MD2SKINS)
  988.         Error ("model.num_skins == MAX_MD2SKINS");
  989.  
  990.     if (g_skipmodel)
  991.         return;
  992.  
  993.     sprintf (name, "%s/%s.lbm", cdarchive, token);
  994.     strcpy (name, ExpandPathAndArchive( name ) );
  995. //    sprintf (name, "%s/%s.lbm", cddir, token);
  996.  
  997.     if (TokenAvailable())
  998.     {
  999.         GetToken (false);
  1000.         sprintf (g_skins[model.num_skins], "%s.pcx", token);
  1001.         sprintf (savename, "%s%s.pcx", gamedir, g_skins[model.num_skins]);
  1002.     }
  1003.     else
  1004.     {
  1005.         sprintf (savename, "%s/%s.pcx", cddir, token);
  1006.         sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token);
  1007.     }
  1008.  
  1009.     model.num_skins++;
  1010.  
  1011.     if (g_skipmodel || g_release || g_archive)
  1012.         return;
  1013.  
  1014.     // load the image
  1015.     printf ("loading %s\n", name);
  1016.     Load256Image (name, &pixels, &palette, &width, &height);
  1017.     RemapZero (pixels, palette, width, height);
  1018.  
  1019.     // crop it to the proper size
  1020.     cropped = malloc (model.skinwidth*model.skinheight);
  1021.     for (y=0 ; y<model.skinheight ; y++)
  1022.     {
  1023.         memcpy (cropped+y*model.skinwidth,
  1024.             pixels+y*width, model.skinwidth);
  1025.     }
  1026.  
  1027.     // save off the new image
  1028.     printf ("saving %s\n", savename);
  1029.     CreatePath (savename);
  1030.     WritePCXfile (savename, cropped, model.skinwidth,
  1031.         model.skinheight, palette);
  1032.  
  1033.     free (pixels);
  1034.     free (palette);
  1035.     free (cropped);
  1036. }
  1037.  
  1038.  
  1039. /*
  1040. =================
  1041. Cmd_Origin
  1042. =================
  1043. */
  1044. void Cmd_Origin (void)
  1045. {
  1046.     // rotate points into frame of reference so model points down the
  1047.     // positive x axis
  1048.     GetToken (false);
  1049.     adjust[1] = -atof (token);
  1050.  
  1051.     GetToken (false);
  1052.     adjust[0] = atof (token);
  1053.  
  1054.     GetToken (false);
  1055.     adjust[2] = -atof (token);
  1056. }
  1057.  
  1058.  
  1059. /*
  1060. =================
  1061. Cmd_ScaleUp
  1062. =================
  1063. */
  1064. void Cmd_ScaleUp (void)
  1065. {
  1066.     GetToken (false);
  1067.     scale_up = atof (token);
  1068.     if (g_skipmodel || g_release || g_archive)
  1069.         return;
  1070.  
  1071.     printf ("Scale up: %f\n", scale_up);
  1072. }
  1073.  
  1074.  
  1075. /*
  1076. =================
  1077. Cmd_Skinsize
  1078.  
  1079. Set a skin size other than the default
  1080. =================
  1081. */
  1082. void Cmd_Skinsize (void)
  1083. {
  1084.     GetToken (false);
  1085.     g_fixedwidth = atoi(token);
  1086.     GetToken (false);
  1087.     g_fixedheight = atoi(token);
  1088. }
  1089.  
  1090. /*
  1091. =================
  1092. Cmd_Modelname
  1093.  
  1094. Gives a different name/location for the file, instead of the cddir
  1095. =================
  1096. */
  1097. void Cmd_Modelname (void)
  1098. {
  1099.     GetToken (false);
  1100.     strcpy (modelname, token);
  1101. }
  1102.  
  1103. /*
  1104. ===============
  1105. Cmd_Cd
  1106. ===============
  1107. */
  1108. void Cmd_Cd (void)
  1109. {
  1110.     FinishModel ();
  1111.     ClearModel ();
  1112.  
  1113.     GetToken (false);
  1114.  
  1115.     // this is a silly mess...
  1116.     sprintf (cdpartial, "models/%s", token); 
  1117.     sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); 
  1118.     sprintf (cddir, "%s%s", gamedir, cdpartial);
  1119.  
  1120.     // if -only was specified and this cd doesn't match,
  1121.     // skip the model (you only need to match leading chars,
  1122.     // so you could regrab all monsters with -only monsters)
  1123.     if (!g_only[0])
  1124.         return;
  1125.     if (strncmp(token, g_only, strlen(g_only)))
  1126.     {
  1127.         g_skipmodel = true;
  1128.         printf ("skipping %s\n", cdpartial);
  1129.     }
  1130. }
  1131.  
  1132.